#include "stdafx.h"
#include "xKernel/IxDescManager.h"
#include "xKernel/IxElement.h"
#include "xKernel/IxAttributeManager.h"
#include "xKernel/IxNode.h"
#include "Builder.h"

CxBuilder::CxBuilder()
{}

CxBuilder::~CxBuilder()
{}

HRESULT CxBuilder::CreateFromFile(BSTR bsFile, IUnknown** ppUnk)
{
    if (!ppUnk)
    {
        return E_POINTER;
    }

    *ppUnk = NULL;

    CComPtr<IxDescManager> spDescMgr;
    ::xCommon::GetService(__uuidof(IxDescManager), (void**)&spDescMgr);
    if (spDescMgr)
    {
        CComPtr<IxPairVec> spDesc;
        spDescMgr->GetDescription(bsFile, &spDesc);
        if (spDesc)
        {
            _create_from_description(spDesc, ppUnk);
        }
    }

    return S_OK;
}

HRESULT CxBuilder::CreateFromDescription(IxPairVec* pVec, IUnknown** ppUnk)
{
    return _create_from_description(pVec, ppUnk);
}

HRESULT CxBuilder::_create_from_description(IxPairVec* pVec, IUnknown** ppUnk)
{
    if (!ppUnk)
    {
        return E_POINTER;
    }

    *ppUnk = NULL;

    if (!pVec)
    {
        return E_FAIL;
    }

    INT nCount = 0;
    pVec->GetCount(&nCount);

    ATLASSERT(nCount <= 3 && nCount > 0);

    if (nCount < 1)
    {
        return E_FAIL;
    }

    CComBSTR bsName;
    pVec->GetName(0, &bsName);

    CComBSTR bsInterface;
    pVec->GetStr(0, &bsInterface);

    if (CString(_T("interface")) == bsName)
    {
        ::xCommon::CreateObjectByInterface(bsInterface, (void**)ppUnk);
        if (!*ppUnk)
        {
            ATLASSERT(!L"create object failure!!!");
            return E_FAIL;
        }
    }
    else
    {
        ATLASSERT(!L"the create info is not correct!!!");
        return E_FAIL;
    }

    if (nCount > 1)
    {
        bsName.Empty();
        pVec->GetName(1, &bsName);

        CComPtr<IxPairVec> spAttribute;
        pVec->GetInterface(1, __uuidof(IxPairVec), (void**)&spAttribute);

        if (spAttribute && CString(_T("attribute")) == bsName)
        {
            CComPtr<IxAttributeManager> spAttriMgr;
            ::xCommon::GetService(__uuidof(IxAttributeManager), (void**)&spAttriMgr);
            if (spAttriMgr)
            {
                spAttriMgr->SetAttribute(*ppUnk, spAttribute);
            }
            else
            {
                ATLASSERT(!L"not find the Attribute Manager!!!");
            }
        }
        else
        {
            ATLASSERT(!L"the create info is not correct!!!");
        }

        if (nCount > 2)
        {
            bsName.Empty();
            pVec->GetName(2, &bsName);

            CComPtr<IxPairVec> spChildren;
            pVec->GetInterface(2, __uuidof(IxPairVec), (void**)&spChildren);

            if (spChildren && CString(_T("children")) == bsName)
            {
                _create_children_from_description(spChildren, CComQIPtr<IxNode>(*ppUnk));
            }
            else
            {
                ATLASSERT(!L"the create info is not correct!!!");
            }
        }
    }

    return S_OK;
}

HRESULT CxBuilder::_create_children_from_description(IxPairVec* pVec, IxNode* pParent)
{
    if (!pVec || !pParent)
    {
        return E_INVALIDARG;
    }

    INT nCount = 0;
    pVec->GetCount(&nCount);

    for (INT i = 0; i < nCount; ++i)
    {
        CComPtr<IxPairVec> spDesc;
        pVec->GetInterface(i, __uuidof(IxPairVec), (void**)&spDesc);

        CComPtr<IUnknown> spUnk;
        _create_from_description(spDesc, &spUnk);

        CComQIPtr<IxNode> spNode = spUnk;
        if (spNode)
        {
            pParent->AddChild(spNode);
        }
        else
        {
            ATLASSERT(!L"child description is not correct!!!");
        }
    }

    return S_OK;
}